using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using ScannerLib.FrameGrabber;
using System.Runtime.InteropServices;
using System.Drawing.Imaging;
using ScannerLib.Tsai;
using ScannerLib.Visualizer;
using System.IO;

namespace Desktop_Scanner
{
    public partial class MainForm : Form
    {
        private Capture m_capture;
        private IntPtr m_lastBitmap = IntPtr.Zero;
        private int m_globalPointCount = 1;
        private CameraCalibrationData m_cameraCalibrationData;
        private AutomaticFinderSettings m_autoFinderSettings = new AutomaticFinderSettings();
        private Bitmap m_autoCalibBitmap = null;
        private bool m_writeFramesToDisk = false;
        

        private List<Bitmap> m_capturedBitmaps = new List<Bitmap>();
        private List<IntPtr> m_capturedIntPtrs = new List<IntPtr>();
        public MainForm()
        {
            InitializeComponent();

            m_capture = new Capture(0, 30, 640, 480);
            m_capture.FrameReady += new EventHandler(FrameReady);

            m_mainTabs.TabPages.Remove(m_calibrationPage);
            m_mainTabs.TabPages.Remove(m_autoCalibrationPage);
            m_mainTabs.TabPages.Remove(m_lightCalibrationTab);

            m_calibrationWindow.CalibrationPoints = new List<CalibrationPoint>();
            m_cmbCalibrationPoints.DataSource = m_calibrationWindow.CalibrationPoints;

            m_lightCalibWindow.CalibrationPoints = new List<PointPair>();
            m_cmbLightCalibrationSamples.DataSource = m_lightCalibWindow.CalibrationPoints;

            m_autoCalibrationPropertyGrid.SelectedObject = m_autoFinderSettings;
            
        }

        #region Camera stuff
        private void UpdateFrame(object sender, EventArgs e)
        {
            if (!m_capture.Started)
                return;

            Bitmap prev = null;
            IntPtr newHandle = IntPtr.Zero;
            try
            {
                newHandle = m_capture.GetBitMap();
            }
            catch (Exception ex)
            {
                return;
            }

            if (m_lastBitmap != IntPtr.Zero)
            {
                if (!m_writeFramesToDisk)
                {
                    prev = m_cameraPicture.Image as Bitmap;
                    Marshal.FreeCoTaskMem(m_lastBitmap);
                }
                else
                {
                    m_capturedBitmaps.Add(m_cameraPicture.Image as Bitmap);
                    m_capturedIntPtrs.Add(m_lastBitmap);
                }
            }

            m_lastBitmap = newHandle;

            Bitmap image = new Bitmap(m_capture.Width, m_capture.Height, m_capture.Stride, PixelFormat.Format24bppRgb, m_lastBitmap);
            //image.RotateFlip(RotateFlipType.RotateNoneFlipY);
            m_cameraPicture.Image = image;

            if (prev != null)
                prev.Dispose();
        }

        private void FrameReady(object sender, EventArgs e)
        {
            if (!m_capture.Started)
                return;

            if (InvokeRequired)
            {
                BeginInvoke(new EventHandler(UpdateFrame), this, e);
            }
            else
            {
                UpdateFrame(this, e);
            }
        }
        #endregion

        private void StartCapture(object sender, EventArgs e)
        {
            
            m_capture.Start();
            m_btnStopCapture.Enabled = true;
            m_btnStartCapture.Enabled = false;
            m_btnCalibrateCamera.Enabled = true;
            m_btnCalibrateLight.Enabled = true;
            m_btnCaptureFrames.Enabled = true;
        }

        private void StopCapture(object sender, EventArgs e)
        {
            m_capture.Pause();
            m_btnStopCapture.Enabled = false;
            m_btnStartCapture.Enabled = true;
            m_btnCalibrateCamera.Enabled = false;
            m_btnCalibrateLight.Enabled = false;
            m_btnCaptureFrames.Enabled = false;
        }

        #region Calibration
        #region Manual Calibration
        private void AdjustCalibrationWindowControls()
        {
            m_lnkAddNewPoint.Text = m_calibrationWindow.AddingNew ? "Save Point" : "Add New Point";
            m_lnkRemoveCurrentPoint.Enabled = m_cmbCalibrationPoints.SelectedItem != null;
            m_lnkCalibrate.Enabled = m_calibrationWindow.CalibrationPoints.Count >= 5;

            if( m_cmbCalibrationPoints.DataSource != null )
                ((CurrencyManager)m_cmbCalibrationPoints.BindingContext[m_cmbCalibrationPoints.DataSource]).Refresh();

            m_calibrationWindow.Refresh();
        }

        private bool m_suspendComboPointSelected = false;
        private void ComboPointSelected(object sender, EventArgs e)
        {
            if (m_suspendComboPointSelected)
                return;

            try
            {
                m_suspendComboPointSelected = true;

                m_calibrationWindow.SelectedPoint = (CalibrationPoint)this.m_cmbCalibrationPoints.SelectedItem;
                
            }
            finally
            {
                m_suspendComboPointSelected = false;
            }
        }

        private bool m_suspendViewPortPointSelected = false;
        private void ViewPortPointSelected(object sender, EventArgs e)
        {
            if (m_suspendViewPortPointSelected)
                return;

            try
            {
                m_suspendViewPortPointSelected = true;
                m_suspendComboPointSelected = true;

                m_cmbCalibrationPoints.SelectedItem = m_calibrationWindow.SelectedPoint;
                m_pointPropertyGrid.SelectedObject = m_calibrationWindow.SelectedPoint;
                AdjustCalibrationWindowControls();

            }
            finally
            {
                m_suspendComboPointSelected = false;
                m_suspendViewPortPointSelected = false;
            }
        }

        private void AddNewPoint(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (m_calibrationWindow.AddingNew)
            {
                m_calibrationWindow.AddingNew = false;
            }
            else
            {
                CalibrationPoint cp = new CalibrationPoint(m_globalPointCount++);
                m_calibrationWindow.CalibrationPoints.Add(cp);
                
                ((CurrencyManager)m_cmbCalibrationPoints.BindingContext[m_cmbCalibrationPoints.DataSource]).Refresh();

                m_calibrationWindow.SelectedPoint= cp;
                
                m_calibrationWindow.AddingNew = true;
                
            }

            AdjustCalibrationWindowControls();
        }

        private void RemoveCurrentPoint(object sender, EventArgs e)
        {
            if (m_calibrationWindow.AddingNew)
                m_calibrationWindow.AddingNew = false;

            if (m_calibrationWindow.SelectedPoint != null)
            {
                int idx = m_calibrationWindow.CalibrationPoints.IndexOf(m_calibrationWindow.SelectedPoint);
                m_calibrationWindow.CalibrationPoints.Remove(m_calibrationWindow.SelectedPoint);
                ((CurrencyManager)m_cmbCalibrationPoints.BindingContext[m_cmbCalibrationPoints.DataSource]).Refresh();

                if (idx == m_calibrationWindow.CalibrationPoints.Count)
                    idx--;

                m_calibrationWindow.SelectedPoint = idx < 0 ? null : m_calibrationWindow.CalibrationPoints[idx];
            }
            

            AdjustCalibrationWindowControls();
            
        }

        private void PerformCalibration(object sender, EventArgs e)
        {
            m_mainTabs.TabPages.Add(m_cameraPage);
            m_mainTabs.TabPages.Remove(m_calibrationPage);

            try
            {
                m_cameraCalibrationData = Calibrator.CalibrateCamera(m_calibrationWindow.CalibrationPoints);
                m_camCalibrationGrid.SelectedObject = m_cameraCalibrationData;
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }

            m_capture.Start();
        }

        private void CalibrateCam(object sender, EventArgs e)
        {
            m_mainTabs.TabPages.Add(m_calibrationPage);
            m_mainTabs.TabPages.Remove(m_cameraPage);

            m_capture.Pause();
            Application.DoEvents();

            if (m_lastBitmap != IntPtr.Zero)
            {
                m_calibrationWindow.Bitmap = (Bitmap)m_cameraPicture.Image;
                m_calibrationWindow.Refresh();
                AdjustCalibrationWindowControls();
            }

        }

        private void CancelCalibration(object sender, LinkLabelLinkClickedEventArgs e)
        {
            m_calibrationWindow.CalibrationPoints.Clear();
            m_calibrationWindow.AddingNew = false;
            ((CurrencyManager)m_cmbCalibrationPoints.BindingContext[m_cmbCalibrationPoints.DataSource]).Refresh();

            m_mainTabs.TabPages.Add(m_cameraPage);
            m_mainTabs.TabPages.Remove(m_calibrationPage);

            m_capture.Start();
        }

        private void CreateCalibrationImage(object sender, EventArgs e)
        {
            using(Bitmap calibrationBitmap = new Bitmap(640, 640,PixelFormat.Format24bppRgb))
            {
                using (Graphics bitmapGraphics = Graphics.FromImage(calibrationBitmap))
                {
                    for (int i = 0; i < 8; i++)
                    {
                        for (int j = 0; j < 8; j++)
                        {
                            Brush b = ((i + j) % 2 == 0) ? Brushes.Black : Brushes.White;

                            bitmapGraphics.FillRectangle(b, j * 80, i * 80, 80, 80);
                        }
                    }
                }

                using (SaveFileDialog sfd = new SaveFileDialog())
                {
                    sfd.DefaultExt = "*.bmp";
                    sfd.Filter = "Bitmap|*.bmp";
                    sfd.SupportMultiDottedExtensions = true;
                    sfd.OverwritePrompt = true;
                    
                    if (sfd.ShowDialog(this) == DialogResult.OK)
                    {
                        try
                        {
                            calibrationBitmap.Save(sfd.FileName);
                        }
                        catch (Exception ex)
                        {
                            MessageBox.Show(this,ex.Message);
                        }
                    }
                }
            }
        }

        #endregion

        #region Automatic Calibration

        private class AutomaticFinderSettings
        {
            private int m_edgeThreshold = 127;
            private int m_houghThreshold = 127;
            private Color m_whiteColor = Color.White;
            private int m_sourceThreshold = 127;
            private double m_houghAngleThreshold = 15;
            private double m_houghDistThreshold = 5;
            private double m_cellSize = 21.0;

            public double CellSize
            {
                get { return m_cellSize; }
                set { m_cellSize = value; }
            }

            public double HoughDistanceThreshold
            {
                get { return m_houghDistThreshold; }
                set { m_houghDistThreshold = value; }
            }

            public double HoughAngleThreshold
            {
                get { return m_houghAngleThreshold; }
                set { m_houghAngleThreshold = value; }
            }
            

            public Color EmptyColor
            {
                get
                {
                    return m_whiteColor;
                }

                set
                {
                    m_whiteColor = value;
                }
            }
            public int EdgeThreshold
            {
                get
                {
                    return m_edgeThreshold;
                }

                set
                {
                    m_edgeThreshold = value;
                }
            }

            public int HoughThreshold
            {
                get
                {
                    return m_houghThreshold;
                }

                set
                {
                    m_houghThreshold = value;
                }
            }

            public int SourceThreshold
            {
                get
                {
                    return m_sourceThreshold;
                }

                set
                {
                    m_sourceThreshold = value;
                }
            }
        }

        private void FindHoughGrid(object sender, EventArgs e)
        {
            string path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "__test.pgm");

            try
            {
                FrameWriter.WritePGM(path, m_autoCalibBitmap);
                KeyValuePair<LineHoughSettings, List<Point>> hough = GridFinder.FindGrid("__test.pgm", m_autoFinderSettings.EdgeThreshold, m_autoFinderSettings.HoughThreshold);

                m_houghVisualizer.HoughSettings = hough.Key;
                m_houghVisualizer.HoughPoints = hough.Value;

                m_houghVisualizer.Refresh();
                AdjustHoughLinks();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }

        }

        private void ViewCalibarionEdges(object sender, EventArgs e)
        {
            string path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "__test.pgm");

            try
            {
                FrameWriter.WritePGM(path, m_autoCalibBitmap);
                m_houghVisualizer.Bitmap = GridFinder.GetEdges(path, m_autoFinderSettings.EdgeThreshold);
                m_houghVisualizer.Refresh();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }
        }

        private  void RestoreOriginalImage(object sender, EventArgs e)
        {
            if (m_autoCalibBitmap != null)
                m_autoCalibBitmap.Dispose();

            Bitmap currentActiveBitmap = m_calibrationWindow.Bitmap;
            m_autoCalibBitmap = new Bitmap(currentActiveBitmap.Width,currentActiveBitmap.Height, currentActiveBitmap.PixelFormat);

            
            Rectangle bounds = new Rectangle(0,0,currentActiveBitmap.Width,currentActiveBitmap.Height);
            BitmapData bdSource = currentActiveBitmap.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format24bppRgb);
            BitmapData bdTarget = m_autoCalibBitmap.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);

            ScannerLib.FrameGrabber.Capture.CopyMemory(bdTarget.Scan0, bdSource.Scan0, bdSource.Stride * bdSource.Height);

            m_autoCalibBitmap.UnlockBits(bdTarget);
            currentActiveBitmap.UnlockBits(bdSource);

            m_houghVisualizer.Bitmap = m_autoCalibBitmap;

            ViewRegular(sender, e);

            Refresh();
        }

        private void ViewHoughTransform(object sender, EventArgs e)
        {
            string path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "__test.pgm");

            try
            {
                FrameWriter.WritePGM(path, m_autoCalibBitmap);
                m_houghVisualizer.Bitmap = GridFinder.GetHough(path, m_autoFinderSettings.EdgeThreshold, m_autoFinderSettings.HoughThreshold);
                m_houghVisualizer.Refresh();
                AdjustHoughLinks();
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }
        }

        private void AttemptAutoCalibration(object sender, EventArgs e)
        {
            m_mainTabs.TabPages.Add(m_autoCalibrationPage);
            m_mainTabs.TabPages.Remove(m_calibrationPage);
            RestoreOriginalImage(this, EventArgs.Empty);
        }

        private void AdjustHoughLinks()
        {
            m_lnkFillRect.Enabled = !m_fillingRect && m_houghVisualizer.Bitmap == m_autoCalibBitmap;
            m_lnkThreshold.Enabled = !m_fillingRect;
            m_lnkViewEdges.Enabled = !m_fillingRect;
            m_lnkViewRegular.Enabled = !m_fillingRect;
            m_lnkHoughRestore.Enabled = !m_fillingRect;
            m_lnkFudgeGridLines.Enabled = !m_fillingRect;
            m_lnkFudgeGridLines.Enabled = !m_fillingRect && m_houghVisualizer.HoughPoints != null;
            m_lnkFindPoints.Enabled = !m_fillingRect && m_houghVisualizer.HoughPoints != null;
        }

        private void CancelAutoCalib(object sender, EventArgs e)
        {
            if (m_fillingRect)
            {
                AdjustHoughLinks();
                m_fillingRect = false;
                return;
            }

            m_mainTabs.TabPages.Add(m_calibrationPage); 
            m_mainTabs.TabPages.Remove(m_autoCalibrationPage);
            

            if (m_autoCalibBitmap != null)
                m_autoCalibBitmap.Dispose();

            m_autoCalibBitmap = null;
        }

        private void ViewRegular(object sender, EventArgs e)
        {
            m_houghVisualizer.Bitmap = m_autoCalibBitmap;
            AdjustHoughLinks();
            Refresh();
        }

        #region Auto calibration drawing
        private void HoughMouseClick(object sender, MouseEventArgs e)
        {
            if (m_houghVisualizer.Bitmap != m_autoCalibBitmap)
                return;

            float x1, x2, y1, y2;

            if (m_fillingRect)
            {
                if (m_fillXS == -1)
                {
                    m_fillXS = e.X;
                    m_fillYS = e.Y;
                    return;
                }
                else
                {
                    m_fillingRect = false;

                    float _x1, _x2, _y1, _y2;

                    _x1 = (m_fillXS) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
                    _y1 = (m_fillYS) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;
                    _x2 = (e.X) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
                    _y2 = (e.Y ) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;


                    x1 = Math.Min(_x1, _x2);
                    x2 = Math.Max(_x1, _x2);
                    y1 = Math.Min(_y1, _y2);
                    y2 = Math.Max(_y1, _y2);

                    Cursor = new Cursor(this.GetType(), "HoughEditCur.cur");
                }
            }
            else
            {
                x1 = (e.X - 16.0f) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
                y1 = (e.Y - 16.0f) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;
                x2 = (e.X + 15.0f) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
                y2 = (e.Y + 15.0f) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;
            }

            using (Graphics bg = Graphics.FromImage(m_autoCalibBitmap))
            {
                using (Brush b = new SolidBrush(m_autoFinderSettings.EmptyColor))
                {
                    bg.FillRectangle(b, x1, y1, x2 - x1, y2 - y1);
                }
            }
            AdjustHoughLinks();
            Refresh();
        }

        private void HoughMouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left || e.X < 0 || e.Y < 0 || e.X >= m_houghVisualizer.Width || e.Y >= m_houghVisualizer.Height || m_houghVisualizer.Bitmap != m_autoCalibBitmap )
                return;

            float x1, x2, y1, y2;

            x1 = (e.X - 16.0f) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
            y1 = (e.Y - 16.0f) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;
            x2 = (e.X + 15.0f) * m_autoCalibBitmap.Width / m_houghVisualizer.Width;
            y2 = (e.Y + 15.0f) * m_autoCalibBitmap.Height / m_houghVisualizer.Height;

            using (Graphics bg = Graphics.FromImage(m_autoCalibBitmap))
            {
                using (Brush b = new SolidBrush(m_autoFinderSettings.EmptyColor))
                {
                    bg.FillRectangle(b, x1, y1, x2 - x1, y2 - y1);
                }
            }

            Refresh();


        }

        private void HoughMouseEnter(object sender, EventArgs e)
        {
            if (!m_fillingRect && m_houghVisualizer.Bitmap == m_autoCalibBitmap)
                Cursor = new Cursor(this.GetType(), "HoughEditCur.cur");
        }

        private void HoughMouseLeave(object sender, EventArgs e)
        {
            Cursor = Cursors.Default;
        }
        #endregion

        #region Image transforms
        private void ThresholdSource(object sender, LinkLabelLinkClickedEventArgs e)
        {
            for (int i = 0; i < m_autoCalibBitmap.Height; i++)
            {
                for (int j = 0; j < m_autoCalibBitmap.Width; j++)
                {
                    Color c = FrameWriter.GrayscaleValue(m_autoCalibBitmap.GetPixel(j, i));
                    m_autoCalibBitmap.SetPixel(j,i, c.R > m_autoFinderSettings.SourceThreshold ? Color.White : Color.Black);
                }
            }

            Refresh();
        }

        private bool m_fillingRect = false;
        private int m_fillXS, m_fillYS;

        private void FillRect(object sender, EventArgs e)
        {
            m_fillXS = -1;
            m_fillingRect = true;
            AdjustHoughLinks();
        }

        private void FudgeGridLines(object sender, LinkLabelLinkClickedEventArgs e)
        {
            List<PointF> list = GridFinder.PruneHoughPoints(m_houghVisualizer.HoughPoints, m_autoFinderSettings.HoughAngleThreshold, m_autoFinderSettings.HoughDistanceThreshold,
                m_houghVisualizer.HoughSettings);
            m_houghVisualizer.HoughPoints = list.ConvertAll<Point>(delegate(PointF p)
            {
                return new Point((int)Math.Round(p.X), (int)Math.Round(p.Y));
            });
            m_houghVisualizer.Refresh();
        }

        private void FindPoints(object sender, LinkLabelLinkClickedEventArgs e)
        {
            string path = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "__test.pgm");

            try
            {
                FrameWriter.WritePGM(path, m_autoCalibBitmap);
                Bitmap b = GridFinder.GetEdges(path, m_autoFinderSettings.EdgeThreshold);

                List<CalibrationPoint> cp = GridFinder.FindCalibrationPoints(b, m_houghVisualizer.HoughPoints,
                    m_autoFinderSettings.HoughAngleThreshold, m_autoFinderSettings.HoughDistanceThreshold, m_houghVisualizer.HoughSettings,m_autoFinderSettings.CellSize);

                CancelAutoCalib(this, e);
                Application.DoEvents();

                m_cmbCalibrationPoints.DataSource = null;
                m_calibrationWindow.CalibrationPoints.Clear();
                m_calibrationWindow.CalibrationPoints.AddRange(cp);
                m_cmbCalibrationPoints.DataSource = m_calibrationWindow.CalibrationPoints;


                

                
                m_calibrationWindow.Refresh();
                AdjustCalibrationWindowControls();

                

                if (cp.Count > 0)
                    m_calibrationWindow.SelectedPoint = cp[0];
            }
            catch (Exception ex)
            {
                MessageBox.Show(this, ex.Message);
            }
        }
        #endregion
        #endregion
        #endregion

        private bool m_ignoreLightPointPairSelected = false;
        private void LightPointPairSelected(object sender, EventArgs e)
        {
            if (m_ignoreLightPointPairSelected)
                return;

            try
            {
                m_ignoreLightPointPairSelected = true;

                m_cmbLightCalibrationSamples.SelectedItem = m_lightCalibWindow.SelectedPoint;

                m_pgLightCalibrationSample.SelectedObject = m_lightCalibWindow.SelectedPoint;
            }
            finally
            {
                m_ignoreLightPointPairSelected = false;
            }
            
            AdjustLightCalibLinks();

        }

        private bool m_ignoreLightPointPairCmdSelected = false;

        private void LightPointPairCmdSelected(object sender, EventArgs e)
        {
            if (m_ignoreLightPointPairCmdSelected)
                return;

            try
            {
                m_ignoreLightPointPairCmdSelected = true;
                m_lightCalibWindow.SelectedPoint = m_cmbLightCalibrationSamples.SelectedItem as PointPair;
            }
            finally
            {
                m_ignoreLightPointPairCmdSelected = false;
            }

            AdjustLightCalibLinks();
        }

        private void AdjustLightCalibLinks()
        {
            m_lnkLCAddNew.Enabled = !m_lightCalibWindow.Changing;
            m_lnkLCCancel.Enabled = m_lightCalibWindow.Changing;
            m_lnkLCChangeEnd.Enabled = !m_lightCalibWindow.ChangingEnd && m_lightCalibWindow.SelectedPoint != null;
            m_lnkLCChangeStart.Enabled = !m_lightCalibWindow.ChangingStart && m_lightCalibWindow.SelectedPoint != null;
            m_lnkLCDone.Enabled = true;
            m_lnkLCRemove.Enabled = !m_lightCalibWindow.Changing && m_lightCalibWindow.SelectedPoint != null;
            m_lnkLCCalibrate.Enabled = !m_lightCalibWindow.Changing && m_lightCalibWindow.CalibrationPoints.Count >= 2;
            Refresh();
        }

        private bool m_addingNew = false;
        private void LCAddNEw(object sender, LinkLabelLinkClickedEventArgs e)
        {

            PointPair pp = new PointPair();
            m_lightCalibWindow.CalibrationPoints.Add(pp);

            ((CurrencyManager)m_cmbLightCalibrationSamples.BindingContext[m_cmbLightCalibrationSamples.DataSource]).Refresh();

            m_lightCalibWindow.SelectedPoint = pp;

            m_lightCalibWindow.ChangingStart = true;


            AdjustLightCalibLinks();
        }

        private void LCRemove(object sender, LinkLabelLinkClickedEventArgs e)
        {
            m_lightCalibWindow.CalibrationPoints.Remove(m_lightCalibWindow.SelectedPoint);
            ((CurrencyManager)m_cmbLightCalibrationSamples.BindingContext[m_cmbLightCalibrationSamples.DataSource]).Refresh();
            m_lightCalibWindow.SelectedPoint = null;

            AdjustLightCalibLinks();
        }

        private void LCChangeStart(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (!m_lightCalibWindow.Changing)
                m_addingNew = false;

            m_lightCalibWindow.ChangingStart = true;
            m_lightCalibWindow.ChangingEnd = false;
            AdjustLightCalibLinks();
        }

        private void LCChangeEnd(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (!m_lightCalibWindow.Changing)
                m_addingNew = false;

            m_lightCalibWindow.ChangingEnd = true;
            m_lightCalibWindow.ChangingStart = false;
            AdjustLightCalibLinks();
        }

        private void LCCancel(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (m_lightCalibWindow.Changing)
            {
                m_lightCalibWindow.ChangingEnd = false;
                m_lightCalibWindow.ChangingStart = false;
            }

            if (m_addingNew)
            {
                m_lightCalibWindow.CalibrationPoints.Remove(m_lightCalibWindow.SelectedPoint);
                ((CurrencyManager)m_cmbLightCalibrationSamples.BindingContext[m_cmbLightCalibrationSamples.DataSource]).Refresh();
                m_lightCalibWindow.SelectedPoint = null;
            }

            AdjustLightCalibLinks();
        }

        private void LCDone(object sender, LinkLabelLinkClickedEventArgs e)
        {
            if (m_lightCalibWindow.Changing)
            {
                m_lightCalibWindow.ChangingEnd = false;
                m_lightCalibWindow.ChangingStart = false;
                m_addingNew = false;
                AdjustLightCalibLinks();
            }
            else
            {
                m_mainTabs.TabPages.Add(m_cameraPage);
                m_mainTabs.TabPages.Remove(m_lightCalibrationTab);

                Application.DoEvents();
                m_capture.Start();
            }
        }

        private void SwitchToLightCalibration(object sender, EventArgs e)
        {
            m_capture.Pause();
            Application.DoEvents();

            


            if (m_lastBitmap != IntPtr.Zero)
            {
                m_mainTabs.TabPages.Add(m_lightCalibrationTab);
                m_mainTabs.TabPages.Remove(m_cameraPage);

                m_lightCalibWindow.Bitmap = (Bitmap)m_cameraPicture.Image;
                m_lightCalibWindow.Refresh();
                AdjustLightCalibLinks();
            }
            else
            {
                m_capture.Start();
            }
        }

        private void m_lnkLCCalibrate_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
        {
            Calibrator.CalibrateLight(m_cameraCalibrationData, m_lightCalibWindow.CalibrationPoints);
        }

        private void CaptureFrames(object sender, EventArgs e)
        {
            string dirName = Path.GetDirectoryName(Application.ExecutablePath) + "\\Capture";
            
            if (!m_writeFramesToDisk )
            {
                m_capturedIntPtrs.Clear();
                m_capturedBitmaps.Clear();


                try
                {
                    if (Directory.Exists(dirName))
                        Directory.Delete(dirName, true);
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.Message);
                    return;
                }

                Directory.CreateDirectory(dirName);

                Application.DoEvents();
                m_writeFramesToDisk = true;
                m_btnCaptureFrames.Text = "Enough!!!";
            }
            else
            {
                m_writeFramesToDisk = false;
                Application.DoEvents();
                m_btnCaptureFrames.Text = "Capture Frames";
                m_btnCaptureFrames.Enabled = false;

                for (int i = 0; i < m_capturedBitmaps.Count; i++)
                {
                    FrameWriter.WritePGM(dirName + "\\Frame" + i + ".pgm", m_capturedBitmaps[i]);
                    Marshal.FreeCoTaskMem(m_capturedIntPtrs[i]);
                    Application.DoEvents();
                }

                m_capturedIntPtrs.Clear();
                m_capturedBitmaps.Clear();

                if (m_cameraCalibrationData != null && m_cameraCalibrationData.LightCalibrationData.Z != 0)
                {
                    if (MessageBox.Show("Create model?", "", MessageBoxButtons.YesNo) == DialogResult.Yes)
                    {
                        Calibrator.CreateModel(m_cameraCalibrationData, dirName);
                    }
                }
            }

            m_btnCaptureFrames.Enabled = true;
            m_btnStopCapture.Enabled = !m_writeFramesToDisk;
            m_btnCreateCalibrationImage.Enabled = !m_writeFramesToDisk;
            m_btnCalibrateCamera.Enabled = !m_writeFramesToDisk;
            m_btnCalibrateLight.Enabled = !m_writeFramesToDisk;
        }
    }
}